package top.scsoul.pas.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.ObjectUtils;
import top.scsoul.pas.bean.XhrResponse;
import top.scsoul.pas.service.UserService;
import top.scsoul.pas.utils.ServletUtil;

import javax.transaction.Transactional;

/**
 *
 */
@Slf4j
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter implements UserDetailsService {
    @Autowired
    PasswordEncoder passwordEncoder;
    @Autowired
    UserService userService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(this).passwordEncoder(passwordEncoder);
    }

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .headers().frameOptions().sameOrigin().and()
                .formLogin()
                .loginPage("/login")
                .usernameParameter("username")
                .passwordParameter("password")
                .loginProcessingUrl("/doLogin")
                .failureUrl("/login")
                .defaultSuccessUrl("/main")
                .and()
                .logout()
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout", "GET"))
                .logoutSuccessUrl("/login");
        http.authorizeRequests()
                .antMatchers("/main/**")
                .hasAnyRole("TEACHER", "ADMIN")
                .and()
                .exceptionHandling().accessDeniedHandler((req, resp, e) -> {
            resp.setCharacterEncoding("UTF-8");
            resp.setContentType("application/json;charset=UTF-8");
            resp.getWriter().write(new ObjectMapper().writeValueAsString(XhrResponse.error(403, "权限不足")));
        });
    }

    @Transactional
    @Override
    public UserDetails loadUserByUsername(String loginName) throws UsernameNotFoundException {
        top.scsoul.pas.entity.User user = userService.login(loginName);
        if (ObjectUtils.isEmpty(user)) {
            log.info("身份验证失败");
            return null;
        }
        if (user.getState() == 0) {
            log.info("账号被锁定");
            return null;
        }
        log.info("身份验证成功");
        StringBuilder sb = new StringBuilder();
        user.getRoles().forEach(role -> {
            log.info("角色{}", role);
            sb.append(role.getName()).append(",");
        });
        ServletUtil.getSession().setAttribute("user", user);
        return new User(user.getLoginName(), user.getPassword(),
                AuthorityUtils.commaSeparatedStringToAuthorityList(sb.toString()));
    }
}